package evolution.problem;

import static java.lang.Math.PI;
import static java.lang.Math.pow;
import static java.lang.Math.sin;

public class MichalewiczMinimization implements OptimizationProblem {

	public static final ProblemConstraints CONSTRAINTS = new ProblemConstraints(
			2, 0, PI);

	private ProblemConstraints constraints = CONSTRAINTS;

	private MichalewiczFitnessFunction fitnessFunction = new MichalewiczFitnessFunction();

	@Override
	public ProblemConstraints getConstraints() {
		return constraints;
	}

	@Override
	public void setConstraints(ProblemConstraints problemConstraints) {
		this.constraints = problemConstraints;
	}

	@Override
	public FitnessFunction getFitnessFunction() {
		return fitnessFunction;
	}

	/**
	 * <a href>http://www.geatbx.com/docu/fcnindex-01.html#P204_10395</a>
	 */
	@Override
	public double getValue(double[] x) {
		int n = x.length;
		int m = 10;
		double sum = 0;

		for (int i = 1; i <= n; i++) {
			double x_i = x[i - 1];
			sum -= sin(x_i) * pow(sin(i * pow(x_i, 2) / PI), 2 * m);
		}

		return sum;
	}

	@Override
	public String getGnuplotFunction() {
		return "-sin(x)*(sin(x*x/pi))**(20) - sin(y)*(sin(2*y*y/pi))**(20)";
	}

	@Override
	public String getGnuplotFunctionName() {
		return "michalewicz";
	}

	public class MichalewiczFitnessFunction implements FitnessFunction {

		@Override
		public double getValue(double[] chromosome) {
			return -MichalewiczMinimization.this.getValue(chromosome);
		}

		@Override
		public double convertToRealValue(double fitnessValue) {
			return -fitnessValue;
		}
	}

	@Override
	public boolean isOptimumValueKnown() {
		return false;
	}

	@Override
	public double getOptimumValue() {
		return Integer.MIN_VALUE;
	}
}
